// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BaseException.cs" company="">
//   
// </copyright>
// <summary>
//   The base exception.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Core
{
    using System;
    using System.Globalization;
    using System.Reflection;
    using System.Runtime.Serialization;

    /// <summary>
    ///   The base exception.
    /// </summary>
    [Serializable]
    public class BaseException : Exception, ISerializable
    {
        #region Fields

        /// <summary>
        ///   The _application name.
        /// </summary>
        private string _applicationName = string.Empty;

        /// <summary>
        ///   The _application version.
        /// </summary>
        private Version _applicationVersion;

        /// <summary>
        ///   The _culture.
        /// </summary>
        private CultureInfo _culture;

        /// <summary>
        ///   The _net version.
        /// </summary>
        private Version _netVersion;

        /// <summary>
        ///   The _operating system.
        /// </summary>
        private OperatingSystem _operatingSystem;

        /// <summary>
        ///   The _ui culture.
        /// </summary>
        private CultureInfo _uiCulture;

        /// <summary>
        ///   The _working set.
        /// </summary>
        private long _workingSet;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        ///   Initializes a new instance of the <see cref="BaseException" /> class.
        /// </summary>
        public BaseException()
        {
            this.Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseException"/> class.
        /// </summary>
        /// <param name="message">
        /// The message. 
        /// </param>
        public BaseException(string message)
            : base(message)
        {
            this.Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseException"/> class.
        /// </summary>
        /// <param name="message">
        /// The message. 
        /// </param>
        /// <param name="innerException">
        /// The inner exception. 
        /// </param>
        public BaseException(string message, Exception innerException)
            : base(message, innerException)
        {
            this.Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseException"/> class.
        /// </summary>
        /// <param name="info">
        /// The info. 
        /// </param>
        /// <param name="context">
        /// The context. 
        /// </param>
        protected BaseException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            try
            {
                var version = info.GetInt32("ApplicationException.Version");
                this._applicationName = info.GetString("ApplicationException.ProductName");
                this._applicationVersion =
                    (Version)info.GetValue("ApplicationException.ProductVersion", typeof(Version));
                this._netVersion = (Version)info.GetValue("ApplicationException.NetVersion", typeof(Version));
                this._operatingSystem =
                    (OperatingSystem)info.GetValue("ApplicationException.OperatingSystem", typeof(OperatingSystem));
                this._culture = (CultureInfo)info.GetValue("ApplicationException.Culture", typeof(CultureInfo));
                this._uiCulture = (CultureInfo)info.GetValue("ApplicationException.UICulture", typeof(CultureInfo));
                this._workingSet = info.GetInt64("ApplicationException.WorkingSet");
            }
            catch (InvalidCastException)
            {
            }
            catch (SerializationException)
            {
            }
        }

        #endregion

        // public String OriginalStackTrace
        // {
        // 	get
        // 	{
        // 		String result = null;
        // 		if (Data.Contains(ExceptionManager.OriginalStackTraceListDataKey))
        // 		{
        // 			List<String> stackList = (List<String>)Data[ExceptionManager.OriginalStackTraceListDataKey];
        // 			result = stackList[0];
        // 		}
        // 		else
        // 		{
        // 			result = StackTrace;
        // 		}
        // 		return result;
        // 	}
        // }
        #region Public Properties

        /// <summary>
        ///   Gets or sets the application name.
        /// </summary>
        public string ApplicationName
        {
            get
            {
                return this._applicationName;
            }

            set
            {
                this._applicationName = value;
            }
        }

        /// <summary>
        ///   Gets or sets the application version.
        /// </summary>
        public Version ApplicationVersion
        {
            get
            {
                return this._applicationVersion;
            }

            set
            {
                this._applicationVersion = value;
            }
        }

        /// <summary>
        ///   Gets or sets the culture.
        /// </summary>
        public CultureInfo Culture
        {
            get
            {
                return this._culture;
            }

            set
            {
                this._culture = value;
            }
        }

        /// <summary>
        ///   Gets or sets the net version.
        /// </summary>
        public Version NetVersion
        {
            get
            {
                return this._netVersion;
            }

            set
            {
                this._netVersion = value;
            }
        }

        /// <summary>
        ///   Gets or sets the operating system.
        /// </summary>
        public OperatingSystem OperatingSystem
        {
            get
            {
                return this._operatingSystem;
            }

            set
            {
                this._operatingSystem = value;
            }
        }

        /// <summary>
        ///   Gets or sets the ui culture.
        /// </summary>
        public CultureInfo UICulture
        {
            get
            {
                return this._uiCulture;
            }

            set
            {
                this._uiCulture = value;
            }
        }

        /// <summary>
        ///   Gets or sets the working set.
        /// </summary>
        public long WorkingSet
        {
            get
            {
                return this._workingSet;
            }

            set
            {
                this._workingSet = value;
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The get object data.
        /// </summary>
        /// <param name="info">
        /// The info. 
        /// </param>
        /// <param name="context">
        /// The context. 
        /// </param>
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("ApplicationException.Version", 0, typeof(Int32));
            info.AddValue("ApplicationException.ProductName", this._applicationName, typeof(String));
            info.AddValue("ApplicationException.ProductVersion", this._applicationVersion, typeof(Version));
            info.AddValue("ApplicationException.NetVersion", this._netVersion, typeof(Version));
            info.AddValue("ApplicationException.OperatingSystem", this._operatingSystem, typeof(OperatingSystem));
            info.AddValue("ApplicationException.Culture", this._culture, typeof(CultureInfo));
            info.AddValue("ApplicationException.UICulture", this._uiCulture, typeof(CultureInfo));
            info.AddValue("ApplicationException.WorkingSet", this._workingSet, typeof(Int64));
        }

        /// <summary>
        ///   The to string.
        /// </summary>
        /// <returns> The <see cref="string" /> . </returns>
        public override string ToString()
        {
            return base.ToString();

            // TODO Refactor
            // ExceptionManager.ExceptionToString(this);
        }

        #endregion

        #region Methods

        /// <summary>
        ///   The initialize.
        /// </summary>
        private void Initialize()
        {
            var entryAssembly = Assembly.GetEntryAssembly();

            if (entryAssembly != null)
            {
                this._applicationName = entryAssembly.GetName().Name;
                this._applicationVersion = entryAssembly.GetName().Version;
            }

            this._netVersion = Environment.Version;
            this._operatingSystem = Environment.OSVersion;
            this._culture = CultureInfo.CurrentCulture;
            this._uiCulture = CultureInfo.CurrentUICulture;
            this._workingSet = Environment.WorkingSet;
        }

        #endregion
    }
}